#include "pantalla.h"
#include "letrasPantalla/letras.h"
#include "letrasPantalla/letras.cpp"

// Variables globales
SDL_Surface *fondo,*j_rojo,*j_azul,*espera,*presenta;
SDL_Surface *pierde,*gana,*campeon,*eliminado,*avanza;
int done = 0;
extern t_scr principal;
SDL_Surface *screen;							// Pantalla SDL
extern int ronda;
int puntaje = 0;
int puntaje_c = 0;
extern bool imprimir;

// Cadenas para impresión en pantalla
extern char nombre1[20];
extern char nombre2[20];
char buffer[20];
char * ronda_str;
char titulo_jugador[]          = "TUX: ";
char titulo_contra[]           = "WIN: ";
char titulo_ronda[]            = "Ronda: ";
char esperando_contrincante[]  = "Esperando... ";
char puntos[]  = "Puntos ";
tipoFuente fuente;

// Mútex para imprimir palabras
extern pthread_mutex_t imprimir_en_pantalla;

// Semáforo del thread pantalla
extern sem_t mutex_pantalla;

// Semáforo del thread periferico
extern sem_t mutex_periferico;

// Semáforo interno de sincronización
sem_t sincro_sdl;

// Semáforos movimientos
extern sem_t nuevo_mov;
extern sem_t sem_mov;
extern sem_t mov_valido;

// Thread actualización
extern pthread_t actualizar;

// Thread
void* thread_pantalla(void* arg)
{
	SDL_Rect dest;
	int ret=-1;

	s_mov* mov = (s_mov*) arg;
  leerFuente(&fuente);
	
	// Funcion inicializacion
	cargar();
	
	// Funcion presentacion
	presentacion();
	
	// Thread actualización
	sem_init(&sincro_sdl,2,1);
	pthread_create(&actualizar, NULL, actualizar_pantalla, NULL);
	
	// Dibujo base gráfica del cliente
	dibujar_base();
	
	while(1)
	{
		// Espero sincronización
		lock_pantalla();
		
		sem_wait(&sincro_sdl);
		
		// Si no hubo cambio en la partida
		if(mov->estado == NO_TERMINO)
			dibujar_grilla();
		
		// Si lo hubo
		else
			switch(mov->estado)
			{
				case GANADOR:											// Cliente ganó la partida
        puntaje++;
				ganador_partida();
				dibujar_grilla();
				break;
			
				case PERDEDOR:										// Cliente perdió la partida
				puntaje_c++;
				perdedor_partida();
				dibujar_grilla();
				break;
				
				case GANADOR_RONDA:								// Cliente ganó la ronda
        puntaje = puntaje_c = 0;
				ganador_ronda();
				dibujar_grilla();
				break;
				
				case CAMPEON:											// Cliente campeón
				campeon_torneo();
				sem_post(&sem_mov);
				sem_post(&sincro_sdl);
				finalizar_sdl();
				break;
				
				case PERDEDOR_RONDA:							// Cliente eliminado
				perdedor_ronda();
				sem_post(&sem_mov);
				sem_post(&sincro_sdl);
				finalizar_sdl();
				break;
			}

		// Mutex estructura movimiento
		sem_post(&sem_mov);
		sem_post(&sincro_sdl);

		// Actualizo pantalla
		SDL_Flip(screen);
	}
}

// Funciones secundarias
void start_sdl()
{
	// Iniciar SDL
	if(SDL_Init(SDL_INIT_VIDEO) < 0)
		error(SDL_GetError());

	atexit(SDL_Quit);
	
	// Modo de video
	screen = SDL_SetVideoMode(WIDTH, HEIGHT, BPP, 0);
	if(screen == NULL)
		error(SDL_GetError());
	
	// Título ventana	
	SDL_WM_SetCaption("TaTeTi Tournament", NULL);
}

void cargar()
{
	// Carga imagenes
	fondo = IMG_Load("recursos/img/fondo_u.png");
	if(fondo == NULL)
		error(SDL_GetError());
	
	j_rojo = IMG_Load("recursos/img/tux2.png");
	if(j_rojo == NULL)
		error(SDL_GetError());
	
	j_azul = IMG_Load("recursos/img/wlogo.png");
	if(j_azul == NULL)
		error(SDL_GetError());
		
	pierde = IMG_Load("recursos/img/perdiste.png");
	if(pierde == NULL)
		error(SDL_GetError());
		
	espera = IMG_Load("recursos/img/esperando.png");
	if(espera == NULL)
		error(SDL_GetError());
			
	gana = IMG_Load("recursos/img/ganaste.png");
	if(gana == NULL)
		error(SDL_GetError());
		
	avanza = IMG_Load("recursos/img/proxima.png");
	if(avanza == NULL)
		error(SDL_GetError());
	
	campeon = IMG_Load("recursos/img/campeon.png");
	if(campeon == NULL)
		error(SDL_GetError());
		
	eliminado = IMG_Load("recursos/img/eliminado.png");
	if(eliminado == NULL)
		error(SDL_GetError());
		
	presenta = IMG_Load("recursos/img/presentacion.png");
	if(presenta == NULL)
		error(SDL_GetError());	
}

void presentacion()
{
	SDL_Rect data;	
	char aux[50];
	
	sprintf(aux,"Bienvenido %s!\0",nombre1);
	data.x = data.y = 0;
	data.w = data.h = presenta->w;
	
	// Imagen presentacion
	SDL_BlitSurface(presenta, NULL, screen, &data);
	
	// Escribo en pantalla
	pthread_mutex_lock(&imprimir_en_pantalla);
	escribirFrase(50,450,aux,&fuente,screen);
	pthread_mutex_unlock(&imprimir_en_pantalla);
	
	SDL_Flip(screen);
	
	sleep(2);
	limpiar_screen();
}

void limpiar_screen()
{
	// Pinto la pantalla de negro
	SDL_FillRect(screen, NULL, 0);
}

void dibujar_grilla()
{
	SDL_Rect dest,origen;
	int i,j;
	
	// Desplazamiento (x,y,ancho_imagen,altura_imagen)
	dest.x = GRID_POSX;
	dest.y = GRID_POSY;
	dest.w = GRID_SIZE;
	dest.h = GRID_SIZE;
	origen.x = GRID_POSX;
	origen.y = GRID_POSY;
	origen.w = GRID_SIZE;
	origen.h = GRID_SIZE;	
	
	// Mando grilla a pantalla
	SDL_BlitSurface(fondo, &origen, screen, &dest);
	
	// Dibujar elementos en la matriz
	dest.w = ANCHO_ITEM;
	dest.h = ANCHO_ITEM;
	
	for(i=0;i<3;i++)
		for(j=0;j<3;j++)
			if(principal.matriz[i][j])
			{
				// Posición de objeto
				dest.x = 10 + GRID_POSX + j*(GRID_SIZE/3);
				dest.y = 10 + GRID_POSY + i*(GRID_SIZE/3);
				
				switch(principal.matriz[i][j])
				{
					case ESFERA:
						SDL_BlitSurface(j_rojo, NULL, screen, &dest);
					break;
					case CUBO:
						SDL_BlitSurface(j_azul, NULL, screen, &dest);
					break;
				}
			}
			
	pthread_mutex_lock(&imprimir_en_pantalla);
	imprimirMarco(75, 500-16, screen);
	escribirFrase(110 , 500 , titulo_jugador, &fuente, screen);
	escribirFrase(110 + fuente.anchoLetra * strlen(titulo_jugador) , 500 , nombre1, &fuente, screen);
	escribirFrase(110 , 500 + fuente.altoLetra , titulo_contra, &fuente, screen);
	
	if(strlen(nombre2) != 0)
			escribirFrase(110 + fuente.anchoLetra * strlen(titulo_contra) , 500 + fuente.altoLetra , nombre2, &fuente, screen);
	else
			escribirFrase(110 + fuente.anchoLetra * strlen(titulo_contra) , 500 + fuente.altoLetra , esperando_contrincante, &fuente, screen);
			
	ronda_str=buffer;
	sprintf(ronda_str, "%d", ronda);
	escribirFrase(110 , 500 + 2 * fuente.altoLetra , titulo_ronda, &fuente, screen);
	escribirFrase(110 + fuente.anchoLetra * strlen(titulo_ronda) , 500 + 2 * fuente.altoLetra , ronda_str, &fuente, screen);

	ronda_str=buffer;
	sprintf(ronda_str, "TUX: %d | WIN: %d", puntaje,puntaje_c);
	escribirFrase(110 , 500 + 3 * fuente.altoLetra , puntos, &fuente, screen);
	escribirFrase(110 + fuente.anchoLetra * strlen(puntos) , 500 + 3 * fuente.altoLetra , ronda_str, &fuente, screen);

	pthread_mutex_unlock(&imprimir_en_pantalla);
	
	// Actualizar pantalla
	SDL_Flip(screen);
}

void dibujar_base()
{
	SDL_Rect dest;
	
	// Desplazamiento (x,y,ancho_imagen,altura_imagen)
	dest.x = dest.y = 0;
	dest.w = fondo -> w;
	dest.h = fondo -> h;
	
	// Mandar fondo a pantalla
	SDL_BlitSurface(fondo, NULL, screen, &dest);
	
	dibujar_grilla();
	
	// Actualizar pantalla
	SDL_Flip(screen);
}

void ganador_partida()
{
	SDL_Rect dest;
	
	// Desplazamiento (x,y,ancho_imagen,altura_imagen)
	dest.x = WIDTH/2  - gana->w/2;
	dest.y = HEIGHT/2 - gana->h/2;
	dest.w = gana -> w;
	dest.h = gana -> h;
	
	// Actualizar pantalla con ganador
	SDL_BlitSurface(gana, NULL, screen, &dest);
	SDL_Flip(screen);
	SDL_Delay(1500);
	limpiar_screen();
	dibujar_base();
}

void perdedor_partida()
{
	SDL_Rect dest;
	
	// Desplazamiento (x,y,ancho_imagen,altura_imagen)
	dest.x = WIDTH/2  - pierde->w/2;
	dest.y = HEIGHT/2 - pierde->h/2;
	dest.w = pierde -> w;
	dest.h = pierde -> h;
	
	// Actualizar pantalla con perdedor
	SDL_BlitSurface(pierde, NULL, screen, &dest);
	SDL_Flip(screen);
	SDL_Delay(1500);
	limpiar_screen();
	dibujar_base();
}

void ganador_ronda()
{
	SDL_Rect dest;
	
	// Desplazamiento (x,y,ancho_imagen,altura_imagen)
	dest.x = WIDTH/2  - avanza->w/2;
	dest.y = HEIGHT/2 - avanza->h/2;
	dest.w = avanza -> w;
	dest.h = avanza -> h;
	
	// Actualizar pantalla con ganador
	SDL_BlitSurface(avanza, NULL, screen, &dest);
	SDL_Flip(screen);
	SDL_Delay(1500);
}

void perdedor_ronda()
{
	SDL_Rect dest;
	
	// Desplazamiento (x,y,ancho_imagen,altura_imagen)
	dest.x = WIDTH/2  - eliminado->w/2;
	dest.y = HEIGHT/2 - eliminado->h/2;
	dest.w = eliminado -> w;
	dest.h = eliminado -> h;
	
	// Actualizar pantalla con perdedor
	SDL_BlitSurface(eliminado, NULL, screen, &dest);
	SDL_Flip(screen);
	SDL_Delay(2000);
}

void campeon_torneo()
{
	SDL_Rect dest;
	
	// Desplazamiento (x,y,ancho_imagen,altura_imagen)
	dest.x = WIDTH/2  - campeon->w/2;
	dest.y = HEIGHT/2 - campeon->h/2;
	dest.w = campeon -> w;
	dest.h = campeon -> h;
	
	// Actualizar pantalla con perdedor
	SDL_BlitSurface(campeon, NULL, screen, &dest);
	SDL_Flip(screen);
	SDL_Delay(2000);
}

int valida_posicion(SDL_Event event)
{
	if(event.button.x > GRID_POSX && event.button.x < GRID_POSX + GRID_SIZE)//(GRID_POSX + ANCHO_ITEM))
		if(event.button.y > GRID_POSY && event.button.y < GRID_POSY + GRID_SIZE)//(GRID_POSY + ANCHO_ITEM))
			return 1;
	return 0;
}

int obtener_posicion(SDL_Event event)
{
	// Convertir coordenada a posición en grilla
	
	int valx = (event.button.x - GRID_POSX);
	int valy = (event.button.y - GRID_POSY);
	valx /= GRID_SIZE/3;
	valy /= GRID_SIZE/3;
	
	switch(valy)
	{
		case 0:
			if(valx == 0) return 0;
			if(valx == 1) return 1;
			else          return 2;
			break;
			
		case 1:
			if(valx == 0) return 3;
			if(valx == 1) return 4;
			else          return 5;
			break;
			
		case 2:
			if(valx == 0) return 6;
			if(valx == 1) return 7;
			else          return 8;
			break;
	}
}

void* thread_lectura(void* arg)
{
	SDL_Event event;
	int ret = -1, done = 0;
	s_mov* mov = (s_mov*) arg;
	
	// Ignorar movimiento mouse y mouse
	SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
	SDL_EventState(SDL_MOUSEBUTTONDOWN, SDL_IGNORE);
	SDL_EventState(SDL_KEYDOWN, SDL_IGNORE);
	
	while(1)
	{
		// Espero sincronismo
		lock_periferico();
		
		printf("Teclado espera ingreso\n");
		event.button.x = event.button.y = done = 0;
		
		// Activo lectura teclado
		SDL_EventState(SDL_MOUSEBUTTONDOWN, SDL_ENABLE);
		SDL_EventState(SDL_KEYDOWN, SDL_ENABLE);
				
		// Espero por evento (espera activa = fix)
		while(!done && SDL_WaitEvent(&event))
		{
			switch(event.type)
			{
				// Si fue ingreso por mouse
				case SDL_MOUSEBUTTONDOWN:
					if(valida_posicion(event))
					{
						// Deshabilito entrada de eventos
						SDL_EventState(SDL_MOUSEBUTTONDOWN, SDL_IGNORE);
						SDL_EventState(SDL_KEYDOWN, SDL_IGNORE);
						
						ret = obtener_posicion(event);
						mov->posicion = ret+1;
						
						// Termino ingreso de eventos
						done = 1;
					}
					break;
				
				// Si fue por teclado (pad numérico)
				case SDL_KEYDOWN:
				{
					switch(event.key.keysym.sym)
					{
						case SDLK_KP1:
							mov->posicion = 7; done = 1; break;
						
						case SDLK_KP2:
							mov->posicion = 8; done = 1; break;
							
						case SDLK_KP3:
							mov->posicion = 9; done = 1; break;
							
						case SDLK_KP4:
							mov->posicion = 4; done = 1; break;
						
						case SDLK_KP5:
							mov->posicion = 5; done = 1; break;
						
						case SDLK_KP6:
							mov->posicion = 6; done = 1; break;
						
						case SDLK_KP7:
							mov->posicion = 1; done = 1; break;
						
						case SDLK_KP8:
							mov->posicion = 2; done = 1; break;	
						
						case SDLK_KP9:
							mov->posicion = 3; done = 1; break;	
					}
					
					if(done)
					{	// Deshabilito entrada de eventos
						SDL_EventState(SDL_MOUSEBUTTONDOWN, SDL_IGNORE);
						SDL_EventState(SDL_KEYDOWN, SDL_IGNORE);
					}
				}
			}
		}
					
		printf("Ingreso válido, oos: %d\n",mov->posicion);
		
		// Aviso mensaje válido a proceso cliente
		sem_post(&nuevo_mov);
	}
}

// Sincronización pantalla
void lock_pantalla()
{
	printf("** Pantalla locked\n");
	sem_wait(&mutex_pantalla);
}

void unlock_pantalla()
{
	printf("** Pantalla unlocked\n");
	sem_post(&mutex_pantalla);
}

// Sincronización periferico
void lock_periferico()
{
	printf("¨¨ Teclado locked\n");
	sem_wait(&mutex_periferico);
}

void unlock_periferico()
{
	printf("¨¨ Teclado unlocked\n");
	sem_post(&mutex_periferico);
}

// Función finalización
void finalizar_sdl()
{
	SDL_FreeSurface(screen);							// Pantalla SDL
	SDL_FreeSurface(fondo);
	SDL_FreeSurface(j_rojo);
	SDL_FreeSurface(j_azul);
	SDL_FreeSurface(gana);
	SDL_FreeSurface(campeon);
	SDL_FreeSurface(avanza);
	SDL_FreeSurface(eliminado);
	
   SDL_Quit();
}

void* actualizar_pantalla(void *data)
{
	SDL_Event evento;

	SDL_EventState(SDL_VIDEOEXPOSE, SDL_IGNORE);
	SDL_EventState(SDL_ACTIVEEVENT, SDL_ENABLE);
	SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
	SDL_EventState(SDL_MOUSEBUTTONDOWN, SDL_IGNORE);

	while(1)
	{
		while(SDL_PollEvent(&evento))
			if(evento.type == SDL_ACTIVEEVENT && evento.active.state==1 & SDL_APPACTIVE)
			{
				// Sincronización
				sem_wait(&sincro_sdl);
				SDL_Flip(screen);
				sem_post(&sincro_sdl);
				printf("Se minimizó, actualicé\n");
			}
			
		sleep(1);
	}
}
